#!/usr/bin/env python3
"""
Configuration Manager for Fortran Code Commentator

Handles loading, validation, and management of system configuration from
multiple sources: files, environment variables, and command-line arguments.
"""

import os
import yaml
import json
import logging
from pathlib import Path
from typing import Dict, Any, Optional, Union, List
from ..core.models import SystemConfiguration

logger = logging.getLogger(__name__)


class ConfigManager:
    """Centralized configuration management system"""
    
    def __init__(self, config_path: Optional[Union[str, Path]] = None):
        self.config_path = Path(config_path) if config_path else None
        self.config = SystemConfiguration()
        self.profiles = {}
        
        # Default configuration locations
        self.default_config_locations = [
            Path.home() / ".fortran-commentator" / "config.yaml",
            Path.cwd() / "fortran-commentator.yaml",
            Path.cwd() / "config" / "fortran-commentator.yaml",
        ]
        
        # Load configuration
        self._load_configuration()
    
    def _load_configuration(self) -> None:
        """Load configuration from available sources in priority order"""
        
        # 1. Load default configuration
        logger.debug("Loading default configuration")
        
        # 2. Load from file if specified or found in default locations
        config_file = self._find_config_file()
        if config_file:
            logger.info(f"Loading configuration from: {config_file}")
            self._load_from_file(config_file)
        
        # 3. Override with environment variables
        self._load_from_environment()
        
        logger.info("Configuration loading completed")
    
    def _find_config_file(self) -> Optional[Path]:
        """Find configuration file in default locations"""
        
        # Use specified path if provided
        if self.config_path and self.config_path.exists():
            return self.config_path
        
        # Search default locations
        for location in self.default_config_locations:
            if location.exists():
                return location
        
        logger.debug("No configuration file found in default locations")
        return None
    
    def _load_from_file(self, config_file: Path) -> None:
        """Load configuration from YAML or JSON file"""
        try:
            with open(config_file, 'r', encoding='utf-8') as f:
                if config_file.suffix.lower() in ['.yaml', '.yml']:
                    data = yaml.safe_load(f)
                elif config_file.suffix.lower() == '.json':
                    data = json.load(f)
                else:
                    logger.warning(f"Unsupported config file format: {config_file.suffix}")
                    return
            
            # Update configuration with file data
            self._update_config_from_dict(data or {})
            
        except Exception as e:
            logger.error(f"Error loading configuration file {config_file}: {e}")
    
    def _load_from_environment(self) -> None:
        """Load configuration overrides from environment variables"""
        env_prefix = "FC_"  # Fortran Commentator prefix
        
        env_mappings = {
            f"{env_prefix}MAX_WORKERS": ("max_workers", int),
            f"{env_prefix}MAX_FILE_LINES": ("max_file_lines", int),
            f"{env_prefix}LLM_URL": ("llm_url", str),
            f"{env_prefix}LLM_MODEL": ("llm_model", str),
            f"{env_prefix}LLM_TIMEOUT": ("llm_timeout", int),
            f"{env_prefix}BACKUP_ENABLED": ("backup_enabled", self._parse_bool),
            f"{env_prefix}LOG_LEVEL": ("log_level", str),
            f"{env_prefix}COMMENT_STYLE": ("comment_style", str),
            f"{env_prefix}VALIDATE_SYNTAX": ("validate_syntax", self._parse_bool),
        }
        
        for env_var, (attr_name, converter) in env_mappings.items():
            value = os.getenv(env_var)
            if value is not None:
                try:
                    converted_value = converter(value)
                    setattr(self.config, attr_name, converted_value)
                    logger.debug(f"Set {attr_name} = {converted_value} from environment")
                except (ValueError, TypeError) as e:
                    logger.warning(f"Invalid value for {env_var}: {value} ({e})")
    
    def _update_config_from_dict(self, data: Dict[str, Any]) -> None:
        """Update configuration from dictionary"""
        for key, value in data.items():
            if hasattr(self.config, key):
                setattr(self.config, key, value)
                logger.debug(f"Set {key} = {value} from config file")
            else:
                logger.warning(f"Unknown configuration key: {key}")
    
    def _parse_bool(self, value: str) -> bool:
        """Parse boolean value from string"""
        return value.lower() in ('true', '1', 'yes', 'on', 'enabled')
    
    def get_config(self) -> SystemConfiguration:
        """Get the current system configuration"""
        return self.config
    
    def update_config(self, **kwargs) -> None:
        """Update configuration with new values"""
        for key, value in kwargs.items():
            if hasattr(self.config, key):
                setattr(self.config, key, value)
                logger.debug(f"Updated {key} = {value}")
            else:
                logger.warning(f"Unknown configuration key: {key}")
    
    def save_config(self, output_path: Optional[Path] = None) -> None:
        """Save current configuration to file"""
        if not output_path:
            output_path = self.config_path or Path.cwd() / "fortran-commentator.yaml"
        
        # Convert config to dictionary
        config_dict = self._config_to_dict()
        
        try:
            with open(output_path, 'w', encoding='utf-8') as f:
                yaml.dump(config_dict, f, default_flow_style=False, indent=2)
            
            logger.info(f"Configuration saved to: {output_path}")
            
        except Exception as e:
            logger.error(f"Error saving configuration to {output_path}: {e}")
    
    def _config_to_dict(self) -> Dict[str, Any]:
        """Convert SystemConfiguration to dictionary"""
        result = {}
        
        for field_name in self.config.__dataclass_fields__:
            value = getattr(self.config, field_name)
            result[field_name] = value
        
        return result
    
    def validate_config(self) -> Dict[str, Any]:
        """Validate current configuration and return validation results"""
        validation_results = {
            "valid": True,
            "errors": [],
            "warnings": [],
            "suggestions": []
        }
        
        # Validate worker count
        if self.config.max_workers < 1:
            validation_results["errors"].append("max_workers must be >= 1")
            validation_results["valid"] = False
        elif self.config.max_workers > 16:
            validation_results["warnings"].append("max_workers > 16 may cause resource issues")
        
        # Validate file size limits
        if self.config.max_file_lines < 10:
            validation_results["errors"].append("max_file_lines must be >= 10")
            validation_results["valid"] = False
        
        # Validate LLM settings
        if not self.config.llm_url:
            validation_results["errors"].append("llm_url cannot be empty")
            validation_results["valid"] = False
        
        if not self.config.llm_model:
            validation_results["errors"].append("llm_model cannot be empty")
            validation_results["valid"] = False
        
        # Validate timeout settings
        if self.config.llm_timeout < 30:
            validation_results["warnings"].append("llm_timeout < 30s may cause premature timeouts")
        
        # Validate retry settings
        if self.config.max_retry_attempts < 1:
            validation_results["errors"].append("max_retry_attempts must be >= 1")
            validation_results["valid"] = False
        
        # Validate comment style
        valid_styles = ["doxygen", "sphinx", "custom"]
        if self.config.comment_style not in valid_styles:
            validation_results["warnings"].append(f"comment_style '{self.config.comment_style}' not in {valid_styles}")
        
        # Validate log level
        valid_levels = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
        if self.config.log_level not in valid_levels:
            validation_results["warnings"].append(f"log_level '{self.config.log_level}' not in {valid_levels}")
        
        return validation_results
    
    def create_profile(self, profile_name: str, **overrides) -> None:
        """Create a configuration profile with specific overrides"""
        base_config = self._config_to_dict()
        base_config.update(overrides)
        
        self.profiles[profile_name] = base_config
        logger.info(f"Created configuration profile: {profile_name}")
    
    def load_profile(self, profile_name: str) -> None:
        """Load a configuration profile"""
        if profile_name not in self.profiles:
            raise ValueError(f"Profile '{profile_name}' not found")
        
        profile_data = self.profiles[profile_name]
        self._update_config_from_dict(profile_data)
        logger.info(f"Loaded configuration profile: {profile_name}")
    
    def list_profiles(self) -> List[str]:
        """List available configuration profiles"""
        return list(self.profiles.keys())


# Create default configuration profiles
def create_default_profiles(config_manager: ConfigManager) -> None:
    """Create standard configuration profiles"""
    
    # Development profile - more verbose, faster processing
    config_manager.create_profile(
        "development",
        log_level="DEBUG",
        max_workers=2,
        progress_report_interval=10,
        backup_enabled=True,
        validate_syntax=True
    )
    
    # Production profile - optimized for performance
    config_manager.create_profile(
        "production", 
        log_level="INFO",
        max_workers=4,
        progress_report_interval=60,
        backup_enabled=True,
        validate_syntax=False  # Skip syntax validation for speed
    )
    
    # Testing profile - minimal settings for unit tests
    config_manager.create_profile(
        "testing",
        log_level="WARNING",
        max_workers=1,
        backup_enabled=False,
        validate_syntax=False,
        max_retry_attempts=1
    )